{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Regressão Linear Múltipla\n",
    "\n",
    "\n",
    "\n",
    "## 1. Introdução\n",
    "\n",
    "Muitos algoritmos de aprendizagem de máquinas utilização métodos de otimização. Esses algoritmos são usados por algoritmos de aprendizado de máquina para encontrar um bom conjunto de parâmetros do modelo, dado um conjunto de dados de treinamento. O algoritmo de otimização mais comum usado na aprendizagem de máquinas é o gradiente descendente estocástico. Neste tutorial, você descobrirá como implementar uma gradiente descendente estocástico para otimizar um algoritmo de regressão linear.\n",
    "\n",
    "Ao final desta aula voce estará apto a:\n",
    "\n",
    "1. Estimar os coeficientes de regressão linear usando a descida gradiente estocástica.\n",
    "2. Fazer previsões para regressão linear multivariada.\n",
    "3. Implementar regressão linear com  gradiente descendente estocástico para fazer previsões em novos dados.\n",
    "\n",
    "### 1.1 Dataset - Seguro de Veículo Sueco\n",
    "\n",
    "Neste tutorial, usaremos o dataset que trata da Qualidade do Vinhos (Wine Quality Data), o qual pode permitir a previsão da qualidade do vinho branco, ajudando o especialista em vinhos na avaliação de qualidade. O RMSE de linha de base do problema é de aproximadamente 0.148 pontos de qualidade. O arquivo winequality-white.csv está disponível no diretório presente. \n",
    "\n",
    "### 1.2 Regressão Linear Multivariada\n",
    "\n",
    "A regressão linear é uma técnica para prever um valor real. Confusamente, esses problemas em que um valor real deve ser previsto são chamados de problemas de regressão. A regressão linear é uma técnica em que uma linha reta é usada para modelar a relação entre valores de entrada e saída. Em mais de duas dimensões, esta linha reta pode ser pensada como um plano ou hiperplano.\n",
    "\n",
    "As previsões são feitas como uma combinação dos valores de entrada para prever o valor de saída. Cada atributo de entrada (x) é ponderado usando um coeficiente (b), e o objetivo do algoritmo de aprendizagem é descobrir um conjunto de coeficientes que resulte em boas previsões (y).\n",
    "\n",
    "\n",
    "![alt text](images/regressao_linear_multipla_modelo.png \"\")\n",
    "                             \n",
    "Os coeficientes podem ser encontrados usando gradiente descendente estocástico.\n",
    "\n",
    "### 1.3 Gradiente Descendente Estocástico\n",
    "\n",
    "Gradiente Descendente é o processo de minimização de uma função seguindo a inclinação ou gradiente dessa função. Na aprendizagem em máquina, podemos usar uma técnica que avalie e atualize os coeficientes de cada iteração chamada gradiente descendente estocástico para minimizar o erro de um modelo em nossos dados de treinamento.\n",
    "\n",
    "A maneira como esse algoritmo de otimização funciona é que cada instância de treinamento é submetida uma de cada vez ao modelo. O modelo faz uma previsão para uma instância de treinamento, o erro é calculado e o modelo é atualizado para reduzir o erro para a próxima previsão. Este processo é repetido para um número fixo de iterações.\n",
    "\n",
    "Esse procedimento pode ser usado para encontrar o conjunto de coeficientes em um modelo que resulte no menor erro para o modelo nos dados de treinamento. Cada iteração, os coeficientes *(b)* são atualizados usando a equação:\n",
    "\n",
    "\n",
    "![alt text](images/coeficiente_b_gradiente.png \"\")\n",
    "\n",
    "\n",
    "Onde *b* é o coeficiente ou o peso a ser otimizado, a *taxa de aprendizado (learning rate)* é uma taxa que você deve configurar (por exemplo, 0,01), o *erro* é o erro de predição para o modelo nos dados de treinamento atribuídos ao peso e *x* é o valor de entrada.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. Tutorial\n",
    "\n",
    "Este tutorial é dividido em 3 partes:\n",
    "\n",
    "1. Fazendo Predições.\n",
    "2. Coeficientes de estimativa. \n",
    "3. Estudo de caso de qualidade do vinho.\n",
    "\n",
    "Isso proporcionará a base que você precisa implementar e aplicar uma regressão linear com descida descendente estocástica em seus próprios problemas de modelagem preditiva.\n",
    "\n",
    "### 2.1 Fazer previsões\n",
    "\n",
    "O primeiro passo é desenvolver uma função que possa fazer previsões. Isso será necessário tanto na avaliação dos valores dos coeficientes do candidato quanto na aplicação do gradiente descendente estocástico. Após o modelo ser finalizado, começaremos a fazer previsões em dados de teste ou novos dados. Abaixo está uma função chamada *predict ()* que prediz um valor de saída para uma linha, dado um conjunto de coeficientes.\n",
    "\n",
    "O primeiro coeficiente é sempre a intercepção, também chamado de viés (em ingles, bias) ou b0, pois é independente e não é responsável por um valor de entrada específico."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# Make a prediction with coefficients\n",
    "def predict(row, coefficients):\n",
    "  yhat = coefficients[0]\n",
    "  for i in range(len(row)-1):\n",
    "    yhat += coefficients[i + 1] * row[i]\n",
    "  return yhat"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exemplo\n",
    "\n",
    "Dado conjunto de dados abaixo, será apresentado o uso da função predict confome exemplo que segue.\n",
    "\n",
    "x |  y\n",
    "--| -\n",
    "1 | 1\n",
    "2 | 3\n",
    "4 | 3\n",
    "3 | 2\n",
    "5 | 5\n",
    "\n",
    "Neste exemplo, existe um único valor de entrada (x) e dois valores de coeficiente (b0 e b1). A equação de predição que modelamos para este problema é:\n",
    "*y = b0 + b1 × x *\n",
    "\n",
    "Ou, com os valores de coeficientes específicos, escolhemos à mão como:\n",
    "y = 0,4 + 0,8 * x \n",
    "\n",
    "Ao executar esta função, obtemos previsões razoavelmente próximas da saída esperada (y) valores."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Esperado=1.000, Predito=1.200\n",
      "Esperado=3.000, Predito=2.000\n",
      "Esperado=3.000, Predito=3.600\n",
      "Esperado=2.000, Predito=2.800\n",
      "Esperado=5.000, Predito=4.400\n"
     ]
    }
   ],
   "source": [
    "# Example of making a prediction with coefficients\n",
    "# Make a prediction\n",
    "def predict(row, coefficients):\n",
    "    yhat = coefficients[0]\n",
    "    for i in range(len(row)-1):\n",
    "        yhat += coefficients[i + 1] * row[i]\n",
    "    return yhat\n",
    "\n",
    "dataset = [[1, 1], [2, 3], [4, 3], [3, 2], [5, 5]]\n",
    "coef = [0.4, 0.8]\n",
    "\n",
    "for row in dataset:\n",
    "  yhat = predict(row, coef)\n",
    "  print(\"Esperado=%.3f, Predito=%.3f\" % (row[-1], yhat))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.2 Estimativa de Coeficientes \n",
    "\n",
    "Para podermos estimar os valores dos coeficientes para nossos dados de treinamento usando gradiente descendente estocástico precisamos definir dois parâmetros:\n",
    "\n",
    "1. Taxa de aprendizado: usado para limitar a quantidade que cada coeficiente é corrigido sempre que é atualizado.\n",
    "2. Épocas: o número de vezes para percorrer os dados de treinamento ao atualizar os coeficientes.\n",
    "\n",
    "Estes parametros, juntamente com os dados de treinamento, serão os argumentos para a função. Existem 3 loops que precisamos executar na função:\n",
    "\n",
    "1. Loop em cada época.\n",
    "2. Faça um loop sobre cada linha nos dados de treinamento para uma época.\n",
    "3. Faça um loop sobre cada coeficiente e atualize-o para uma linha dos dados em uma época.\n",
    "\n",
    "Como você pode ver, atualizamos cada coeficiente para cada linha nos dados de treinamento, em cada época. Os coeficientes são atualizados com base no erro que o modelo fez. O erro é calculado como a diferença entre a previsão feita com os coeficientes do candidato e o valor de saída esperado.\n",
    "\n",
    "*error = prediction − expected*\n",
    "\n",
    "Existe um coeficiente para ponderar cada atributo de entrada, e estes são atualizados de forma consistente, por exemplo:\n",
    " \n",
    "b1 (t + 1) = b1 (t) - taxa de aprendizado x erro (t) x x1 (t)\n",
    "\n",
    "\n",
    "O coeficiente especial no início da lista, também chamado de intercepção ou a polarização, é atualizado de forma semelhante, exceto sem uma entrada porque não está associado a um valor de entrada específico:\n",
    "\n",
    "b0 (t + 1) = b0 (t) - taxa de aprendizagem * erro (t) \n",
    "\n",
    "Abaixo está uma função denominada coefficients_sgd() que calcula valores de coeficientes para um conjunto de dados de treinamento usando gradiente descendente estocástico.\n",
    "\n",
    "Usamos uma pequena taxa de aprendizado de 0,001 e treinamos o modelo por 50 épocas, ou 50 exposições dos coeficientes para todo o conjunto de dados de treinamento. Ao executar o exemplo, imprime uma mensagem a cada época com o erro de soma quadrada para aquela época e o conjunto final de coeficientes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Coeficiente Inicial={0}\n",
      "epoch=0, lrate=0.001, error=46.236\n",
      "epoch=1, lrate=0.001, error=41.305\n",
      "epoch=2, lrate=0.001, error=36.930\n",
      "epoch=3, lrate=0.001, error=33.047\n",
      "epoch=4, lrate=0.001, error=29.601\n",
      "epoch=5, lrate=0.001, error=26.543\n",
      "epoch=6, lrate=0.001, error=23.830\n",
      "epoch=7, lrate=0.001, error=21.422\n",
      "epoch=8, lrate=0.001, error=19.285\n",
      "epoch=9, lrate=0.001, error=17.389\n",
      "[0.10710331074898374, 0.3801081881174074]\n"
     ]
    }
   ],
   "source": [
    "# Estimate linear regression coefficients using stochastic gradient descent\n",
    "def coefficients_sgd(train, l_rate, n_epoch):\n",
    "    coef = [0.0 for i in range(len(train[0]))]\n",
    "    print ('Coeficiente Inicial={0}' % (coef))\n",
    "    for epoch in range(n_epoch):\n",
    "        sum_error = 0\n",
    "        for row in train:\n",
    "            yhat = predict(row, coef)\n",
    "            error = yhat - row[-1]\n",
    "            sum_error += error**2\n",
    "            coef[0] = coef[0] - l_rate * error\n",
    "            for i in range(len(row)-1):\n",
    "                coef[i + 1] = coef[i + 1] - l_rate * error * row[i] \n",
    "        print(('epoch=%d, lrate=%.3f, error=%.3f' % (epoch, l_rate, sum_error)))\n",
    "    return coef\n",
    "\n",
    "# Calculate coefficients\n",
    "dataset = [[1, 1], [2, 3], [4, 3], [3, 2], [5, 5]]\n",
    "l_rate = 0.001\n",
    "n_epoch = 10\n",
    "coef = coefficients_sgd(dataset, l_rate, n_epoch)\n",
    "print(coef)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
